/*
 *
 *
 * ansic.y: PCYACC grammar description for ANSI C
 * version 1.0
 * by Xing Liu
 *
 * PCYACC (R) ABRAXAS SOFTWARE, ALL RIGHT RESERVED.
 *
 * Reference: The C Programming Language (Reference Manual)
 *            Second Edition
 *            By B.W. Kernighan and D.M. Retchie
 *
 */

%union {
    int   i;
    float r;
    char *s;
};

/*
 * special symbols
 */
%token DDD      /* three dots ... */

/*
 * constants
 */
%token  CHARACTER_CONSTANT FLOAT_CONSTANT INTEGER_CONSTANT STRING

/*
 * identifiers
 */
%token  IDENTIFIER TYPENAME ENUMERATION_CONSTANT

/*
 * key words
 */
%token  Auto        Break       Case        Char        Const
%token	Continue	Default		Do  	 	Double		Else
%token	Enum		Extern 		Float		For		Goto
%token  If          Int         Long        Register    Return
%token	Short		Signed 		Sizeof	 	Static		Struct
%token	Switch		Typedef		Void 	  	Volatile	Union
%token	Unsigned	While

/*
 * combined operators
 */

/*
 * binary logicals and comparators
 */
%token  OROR    ANDAND  EQU NEQ LEQ GEQ

/*
 * shift operators
 */
%token  SHL SHR

/*
 * unary increments
 */
%token  ADDADD  SUBSUB

/*
 * pointer
 */
%token  PTR

/*
 * assignments
 */
%token  ADDEQ   SUBEQ   MULEQ   DIVEQ   MODEQ
%token	SHLEQ	SHREQ	ANDEQ	XOREQ	IOREQ

/*
 * operator precedence
 */

/*
 * comma operator
 */
%left   ','

/*
 * assignment operators
 */
%right ADDEQ SUBEQ MULEQ DIVEQ MODEQ SHLEQ SHREQ BANDEQ BXOREQ BOREQ

/*
 * binary operators
 */
%right  '?' ':'
%left	OROR
%left	ANDAND
%left	BOR
%left	BEOR
%left	BAND
%left	EQU
%left	NEQ
%left	LEQ	GEQ
%left	SHL	SHR
%left	ADD	SUB
%left	MUL	DIV	MOD

/*
 * unary operators
 */
%right ADDADD SUBSUB '~' '!' UNIADD UNISUB UNIMUL UNIBAND Sizeof '*'

/*
 * special operators
 */
%left '(' '[' '.' PTR

/*
 * start symbol
 */
%start translation_unit

%%

translation_unit :                  external_declaration
                 | translation_unit external_declaration
                 ;

external_declaration : function_definition
                     | declaration
                     ;

function_definition :
    declaration_specifiers declarator declaration_list compound_statement
  | declaration_specifiers declarator                  compound_statement
  |                        declarator declaration_list compound_statement
  |                        declarator                  compound_statement
  ;

declaration : declaration_specifiers init_declarator_list ';'
            | declaration_specifiers                      ';'
            ;

declaration_list :                  declaration
                 | declaration_list declaration
                 ;

declaration_specifiers :                        declaration_specifier
                       | declaration_specifiers declaration_specifier
                       ;

declaration_specifier : storage_class_specifier
                      | type_specifier
                      | type_qualifier
                      ;

storage_class_specifier : Auto
                        | Extern
                        | Register
                        | Static
                        /*
                         * need to insert type names into symbols table
                         */
                        | Typedef
                        ;

type_specifier : Char
               | Double
               | Float
               | Int
               | Long
               | Short
               | Signed
               | Unsigned
               | Void
               | TYPENAME
               | aggregate_specifier
               ;

type_qualifier : Const
               | Volatile
               ;

aggregate_specifier : aggregate_type IDENTIFIER '{' aggregate_member_list '}'
                    | aggregate_type            '{' aggregate_member_list '}'
                    | aggregate_type IDENTIFIER
                    ;

aggregate_type : Enum
               | Struct
               | Union
               ;

aggregate_member_list : struct_declaration_list
                      | enumerator_list
                      ;

struct_declaration_list :                         struct_declaration
                        | struct_declaration_list struct_declaration
                        ;

init_declarator_list :                          init_declarator
                     | init_declarator_list ',' init_declarator
                     ;

init_declarator : declarator
                | declarator '=' initializer
                ;

struct_declaration : declaration_specifiers struct_declarator_list ';'
                   ;

struct_declarator_list :                            struct_declarator
                       | struct_declarator_list ',' struct_declarator
                       ;

struct_declarator : declarator
                  | declarator ':' constant_expression
                  |            ':' constant_expression
                  ;

enumerator_list :                     enumerator
                | enumerator_list ',' enumerator
                ;

/*
 * need to insert enumeration names into symbol table
 */
enumerator : IDENTIFIER
           | IDENTIFIER '=' constant_expression
           ;

declarator : pointer direct_declarator
           |         direct_declarator
           ;

direct_declarator : IDENTIFIER
                  | '(' declarator ')'
                  | direct_declarator '[' constant_expression ']'
                  | direct_declarator '['                     ']'
                  | direct_declarator '(' parameter_type_list ')'
                  | direct_declarator '(' identifier_list     ')'
                  | direct_declarator '('                     ')'
                  ;

pointer : '*' type_qualifier_list
        | '*'
        | '*' type_qualifier_list pointer
        | '*'                     pointer
        ;

type_qualifier_list :                     type_qualifier
                    | type_qualifier_list type_qualifier
                    ;

parameter_type_list : parameter_list
                    | parameter_list ',' DDD
                    ;

parameter_list :                    parameter_declaration
               | parameter_list ',' parameter_declaration
               ;

parameter_declaration : declaration_specifiers declarator
                      | declaration_specifiers abstract_declarator
                      | declaration_specifiers
                      ;

identifier_list :                     IDENTIFIER
                | identifier_list ',' IDENTIFIER
                ;

initializer : assignment_expression
            | '{' initializer_list '}'
            | '{' initializer_list ',' '}'
            ;

initializer_list :                      initializer
                 | initializer_list ',' initializer
                 ;

type_name : declaration_specifiers abstract_declarator
          | declaration_specifiers
          ;

abstract_declarator : pointer
                    | pointer direct_abstract_declarator
                    |         direct_abstract_declarator
                    ;

direct_abstract_declarator :
              '(' abstract_declarator ')'
            | direct_abstract_declarator '[' constant_expression ']'
            | direct_abstract_declarator '['                     ']'
            |                            '[' constant_expression ']'
            |                            '['                     ']'
            | direct_abstract_declarator '(' parameter_type_list ')'
            | direct_abstract_declarator '('                     ')'
            |                            '(' parameter_type_list ')'
            |                            '('                     ')'
            ;

statement : labeled_statement
          | expression_statement
          | compound_statement
          | selection_statement
          | iteration_statement
          | jump_statement
          ;

labeled_statement : IDENTIFIER ':'               statement
                  | Case constant_expression ':' statement
                  | Default ':'                  statement
                  ;

expression_statement : expression ';'
                     |            ';'
                     ;

compound_statement : '{' declaration_list statement_list '}'
                   | '{' declaration_list                '}'
                   | '{'                  statement_list '}'
                   | '{'                                 '}'
                   ;

statement_list :                statement
               | statement_list statement
               ;

selection_statement : If '(' expression ')'     statement
                    | If '(' expression ')'     statement Else statement
                    | Switch '(' expression ')' statement
                    ;

iteration_statement :
              While '(' expression ')' statement
            | Do statement While '(' expression ')' ';'
            | For '(' expression ';' expression ';' expression ')' statement
            | For '(' expression ';' expression ';'            ')' statement
            | For '(' expression ';'            ';' expression ')' statement
            | For '(' expression ';'            ';'            ')' statement
            | For '('            ';' expression ';' expression ')' statement
            | For '('            ';' expression ';'            ')' statement
            | For '('            ';'            ';' expression ')' statement
            | For '('            ';'            ';'            ')' statement
            ;

jump_statement : Goto IDENTIFIER   ';'
               | Continue          ';'
               | Break             ';'
               | Return expression ';'
               | Return            ';'
               ;

expression :                assignment_expression
           | expression ',' assignment_expression
           ;

assignment_expression :
              conditional_expression
            | unary_expression assignment_operator assignment_expression
            ;

assignment_operator : '='
                    | MULEQ
                    | DIVEQ
                    | MODEQ
                    | ADDEQ
                    | SUBEQ
                    | SHLEQ
                    | SHREQ
                    | ANDEQ
                    | IOREQ
                    | XOREQ
                    ;

conditional_expression :
              logical_or_expression
            | logical_or_expression '?' expression ':' conditional_expression
            ;

constant_expression : conditional_expression
                    ;

logical_or_expression :                            logical_and_expression
                      | logical_or_expression OROR logical_and_expression
                      ;

logical_and_expression :                               inclusive_or_expression
                       | logical_and_expression ANDAND inclusive_or_expression
                       ;

inclusive_or_expression :                             exclusive_or_expression
                        | inclusive_or_expression '|' exclusive_or_expression
                        ;

exclusive_or_expression :                             and_expression
                        | exclusive_or_expression '^' and_expression
                        ;

and_expression :                    equality_expression
               | and_expression '&' equality_expression
               ;

equality_expression :                         relational_expression
                    | equality_expression EQU relational_expression
                    | equality_expression NEQ relational_expression
                    ;

relational_expression :                           shift_expression
                      | relational_expression '<' shift_expression
                      | relational_expression '>' shift_expression
                      | relational_expression LEQ shift_expression
                      | relational_expression GEQ shift_expression
                      ;
			     
shift_expression :                      additive_expression
                 | shift_expression SHL additive_expression
                 | shift_expression SHR additive_expression
                 ;

additive_expression :                         multiplicative_expression
                    | additive_expression '+' multiplicative_expression
                    | additive_expression '-' multiplicative_expression
                    ;

multiplicative_expression :                               cast_expression
                          | multiplicative_expression '*' cast_expression
                          | multiplicative_expression '/' cast_expression
                          | multiplicative_expression '%' cast_expression
                          ;

cast_expression : unary_expression
                | '(' type_name ')' cast_expression
                ;

unary_expression : postfix_expression
                 | ADDADD unary_expression
                 | SUBSUB unary_expression
                 | unary_operator cast_expression
                 | Sizeof unary_expression
                 | Sizeof '(' type_name ')'
                 ;

unary_operator : '&'
               | '*'
               | '+'
               | '-'
               | '~'
               | '!'
               ;

postfix_expression : primary_expression
                   | postfix_expression '[' expression ']'
                   | postfix_expression '(' argument_expression_list ')'
                   | postfix_expression '('                          ')'
                   | postfix_expression '.' IDENTIFIER
                   | postfix_expression PTR IDENTIFIER
                   | postfix_expression ADDADD
                   | postfix_expression SUBSUB
                   ;

primary_expression : IDENTIFIER
                   | constant
                   | STRING
                   | '(' expression ')'
                   ;

argument_expression_list :                              assignment_expression
                         | argument_expression_list ',' assignment_expression
                         ;

constant : INTEGER_CONSTANT
         | CHARACTER_CONSTANT
         | FLOAT_CONSTANT
         | ENUMERATION_CONSTANT
         ;
